package com.wolfword.crawler.server.service.impl;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.io.FileUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.github.pagehelper.PageHelper;
import com.wolfword.common.enums.ClientStatusEnum;
import com.wolfword.common.enums.CrawlStatusEnum;
import com.wolfword.common.util.object.StringUtil;
import com.wolfword.common.util.password.Base64Util;
import com.wolfword.crawler.server.dao.CrawlTaskDao;
import com.wolfword.crawler.server.dao.RequestLogDao;
import com.wolfword.crawler.server.dto.CrawlTask4ParentDto;
import com.wolfword.crawler.server.dto.CrawlTaskWithHtmlDto;
import com.wolfword.crawler.server.dto.RequestLogDto;
import com.wolfword.crawler.server.entity.CrawlTaskEntity;
import com.wolfword.crawler.server.entity.RequestLogEntity;
import com.wolfword.crawler.server.service.CrawlTaskService;
import com.wolfword.crawler.server.service.RequestLogService;

@Service
public class CrawlTaskServiceImpl implements CrawlTaskService {
	
	@Value("${html.temp.path}")
	private String htmlTempPath;
	@Value("${html.store.path}")
	private String htmlStorePath;
	
	@Autowired
	private CrawlTaskDao crawlTaskDao;
	@Autowired
	private RequestLogDao requestLogDao;
	@Autowired
	private RequestLogService requestLogService;
	

	public CrawlTaskDao getCrawlTaskDao() {
		return crawlTaskDao;
	}

	@Resource
	public void setCrawlTaskDao(CrawlTaskDao crawlTaskDao) {
		this.crawlTaskDao = crawlTaskDao;
	}

	/**
	 * 插入数据
	 *
	 * @param entity
	 *            实体类
	 * @return 主键值
	 */
	@Override
	public long insert(CrawlTaskEntity entity) {
		crawlTaskDao.insert(entity);
		return entity.getId();
	}

	/**
	 * 批量插入数据
	 *
	 * @param list
	 *            实体类
	 */
	@Override
	public void batchInsert(List<CrawlTaskEntity> list) {
		crawlTaskDao.batchInsert(list);
	}

	/**
	 * 根据主键更新数据
	 *
	 * @param entity
	 *            新数据
	 */
	@Override
	public Integer updateByPrimary(CrawlTaskEntity entity) {
		return crawlTaskDao.updateByPrimary(entity);
	}

	/**
	 * 根据主键获取数据
	 *
	 * @param entity
	 *            查询条件
	 * @return 查询结果
	 */
	@Override
	public CrawlTaskEntity getByPrimary(CrawlTaskEntity entity) {
		return crawlTaskDao.getByPrimary(entity);
	}

	/**
	 * 根据查询条件获取一条记录
	 *
	 * @param conditions
	 *            查询条件
	 * @return 查询结果
	 */
	@Override
	public CrawlTaskEntity getOne(Map<String, Object> conditions) {
		return crawlTaskDao.getOne(conditions);
	}

	/**
	 * 根据查询条件查询
	 *
	 * @param conditions
	 *            查询条件
	 * @return 结果集
	 */
	@Override
	public List<CrawlTaskEntity> queryList(Map<String, Object> conditions) {
		return crawlTaskDao.queryList(conditions);
	}

	/**
	 * 查询所有数据
	 *
	 * @return 结果集
	 */
	@Override
	public List<CrawlTaskEntity> getAll() {
		return crawlTaskDao.getAll();
	}
	
	/**
	 * 获取待处理任务列表
	 * @param clientName
	 * @param clientIp
	 * @param clientPort
	 * @param taskCount
	 * @return
	 * @author ServerZhang
	 * @date 2018年1月11日
	 */
	@Override
	@Transactional
	public List<CrawlTaskEntity> listUncrawled(String clientName, String clientIp, 
			Integer clientPort, Integer taskCount) {
		//1.获取数据
		List<CrawlTaskEntity> listUncrawled = crawlTaskDao.listUncrawled(taskCount);
		
		if (null == listUncrawled ||listUncrawled.size() < 1) {
			return null;
		}
		
		//2.记录客户端请求
		RequestLogEntity logEntity = new RequestLogEntity();
		logEntity.setClientIp(clientIp);
		logEntity.setClientName(clientName);
		logEntity.setClientPort(clientPort);
		logEntity.setClientStatus(ClientStatusEnum.WORKING.getStatus());//客户端状态：0无响应，1待机，2工作中
		logEntity.setRequestCount(listUncrawled.size());
		
		Long logId = requestLogService.insert(logEntity);
		if (logId < 1) {//保存失败
			return null;
		}
		
		//3.修改任务状态及请求主机信息
		Iterator<CrawlTaskEntity> iterator = listUncrawled.iterator();
		/*CrawlTaskEntity firstEntity = iterator.next();
		if (firstEntity == null) {
			return null;
		}*/
		//StringBuffer idBuffer = new StringBuffer();
		List<Long> ids = new ArrayList<Long>();
		/*idBuffer.append(firstEntity.getId());
		firstEntity.setRequestLogId(logId);*/
		while(iterator.hasNext()){
			CrawlTaskEntity next = iterator.next();
			next.setRequestLogId(logId);
			Long id = next.getId();
			if (null == id) {
				continue;
			}
			ids.add(id);
			//idBuffer.append(",").append(id);
		}
		
		crawlTaskDao.changeStatus(ids, CrawlStatusEnum.CRAWLING.getStatus(), logId, clientName, clientIp, clientPort);
		
		return listUncrawled;
	}
	
	/**
	 * 从缓存文件夹中批量添加任务
	 * @author ServerZhang
	 * @date 2018年1月19日
	 */
	@Override
	@Deprecated
	public synchronized void insertTask(){
		//从暂存目录获取json文件
		if (StringUtil.isEmpty(htmlTempPath)) {
			htmlTempPath = "./temp/";
		}
		File pFile = new File(htmlTempPath);
		if (!pFile.exists()) {
			return;
		}
		File[] files = pFile.listFiles();
		if (files.length < 1) {
			return;
		}
		File file = files[0];
		
		String jsonStr = null;
		try {
			jsonStr = FileUtils.readFileToString(file, "UTF-8");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			if (jsonStr == null) {
				if (file.exists()) {
					file.delete();
				}
				return;
			}
		}
		
		List<CrawlTaskEntity> entities = new ArrayList<CrawlTaskEntity>();
		List<CrawlTaskWithHtmlDto> dtos = new ArrayList<CrawlTaskWithHtmlDto>();
		JSONArray jsonArray = new JSONArray(jsonStr);
		int length = jsonArray.length();
		if (length < 1) {
			if (file.exists()) {
				file.delete();
			}
			return;
		}
		
		for(int i=0; i<length; i++){//遍历得到一个对象
			Object object = jsonArray.get(i);
			if (null == object) {
				continue;
			}
			CrawlTaskEntity entity = new CrawlTaskEntity();
			
			CrawlTaskWithHtmlDto dto = new CrawlTaskWithHtmlDto();
			
			JSONObject jsonObject = new JSONObject(object.toString());
			Iterator keys = jsonObject.keys();
			while(keys.hasNext()){//遍历对象中的键值
				Object keyObj = keys.next();
				if (null == keyObj) {
					continue;
				}
				String key = keyObj.toString();
				Object valueObj = jsonObject.get(key);
				if (StringUtil.isEmpty(valueObj)) {
					continue;
				}
				String value = valueObj.toString();
				switch (key) {
				case "parentId":
					entity.setParentId(Long.parseLong(value));
					break;
				case "url":
					entity.setUrl(value);
					break;
				case "urlShort":
					entity.setUrlShort(value);
					dto.setUrlShort(value);
					break;
				case "parentUrl":
					entity.setParentUrl(value);
					break;
				case "parentUrlShort":
					entity.setParentUrlShort(value);
					break;
				case "rootUrlId":
					entity.setRootUrlId(Long.parseLong(value));
					break;
				case "containStr":
					entity.setContainStr(value);
					break;
				case "storePath":
					entity.setStorePath(value);
					dto.setStorePath(value);
					break;
				case "mailCount":
					entity.setMailCount(Integer.parseInt(value));
					break;
				case "phoneCount":
					entity.setPhoneCount(Integer.parseInt(value));
					break;
				case "titleCount":
					entity.setTitleCount(Integer.parseInt(value));
					break;
				case "htmlStr":
					dto.setHtmlStr(value);
					break;
				default:
					break;
				}
			}
			entities.add(entity);
			dtos.add(dto);
		}
		
		//批量插入
		crawlTaskDao.batchInsert(entities);
		
		//上传文件
		Iterator<CrawlTaskWithHtmlDto> iterator = dtos.iterator();
		while(iterator.hasNext()){
			CrawlTaskWithHtmlDto next = iterator.next();
			String htmlStr = next.getHtmlStr();
			String storePath = next.getStorePath();
			String urlShort = next.getUrlShort();
			if (StringUtil.isEmpty(htmlStr,storePath,urlShort)) {
				continue;
			}
			if (StringUtil.isEmpty(htmlStorePath)) {
				htmlStorePath = "./htmls/";
			}
			String folderPath = StringUtil.connectAsFilePath(htmlStorePath,storePath);
			File folder = new File(folderPath);
			if (!folder.exists()) {
				folder.mkdirs();
			}
			String realFilePath = folderPath+"/"+urlShort+".html";
			File tempFile = new File(realFilePath);
			if (!tempFile.exists()) {
				try {
					tempFile.createNewFile();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			
			
			// 将html内容写入文件
			Writer writer = null;
			try {
				htmlStr = Base64Util.decrypt2Str(htmlStr);
				writer = new BufferedWriter(new OutputStreamWriter(
						new FileOutputStream(realFilePath), "UTF-8"));
				writer.write(htmlStr);
				writer.close();
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} finally{
				try {
					if (writer != null) {
						writer.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
		//文件上传完成后，删除缓存文件
		if (file.exists()) {
			file.delete();
		}
	}
	/**
	 * 从缓存文件夹中批量修改任务
	 * @author ServerZhang
	 * @date 2018年1月26日
	 */
	@Override
	public synchronized void updateTask4File(){
		//从暂存目录获取json文件
		if (StringUtil.isEmpty(htmlTempPath)) {
			htmlTempPath = "./temp/";
		}
		File pFile = new File(htmlTempPath);
		if (!pFile.exists()) {
			return;
		}
		File[] files = pFile.listFiles();
		if (files.length < 1) {
			return;
		}
		File file = files[0];
		
		String jsonStr = null;
		try {
			jsonStr = FileUtils.readFileToString(file, "UTF-8");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			if (jsonStr == null) {
				if (file.exists()) {
					file.delete();
				}
				return;
			}
		}
		updateTask(jsonStr);
		
		//删除缓存文件
		if (file.exists()) {
			file.delete();
		}
	}
	/**
	 * 批量添加任务
	 * @param jsonStr 任务列表json串
	 * @author ServerZhang
	 * @date 2018年1月11日
	 */
	@Override
	public void insertTask(String jsonStr){
		List<CrawlTaskEntity> list = new ArrayList<CrawlTaskEntity>();
		JSONArray jsonArray = new JSONArray(jsonStr);
		int length = jsonArray.length();
		if (length < 1) {
			return;
		}
		for(int i=0; i<length; i++){//遍历得到一个对象
			Object object = jsonArray.get(i);
			if (null == object) {
				continue;
			}
			CrawlTaskEntity entity = new CrawlTaskEntity();
			
			JSONObject jsonObject = new JSONObject(object.toString());
			Iterator keys = jsonObject.keys();
			while(keys.hasNext()){//遍历对象中的键值
				Object keyObj = keys.next();
				if (null == keyObj) {
					continue;
				}
				String key = keyObj.toString();
				Object valueObj = jsonObject.get(key);
				if (StringUtil.isEmpty(valueObj)) {
					continue;
				}
				String value = valueObj.toString();
				switch (key) {
				case "parentId":
					entity.setParentId(Long.parseLong(value));
					break;
				case "url":
					entity.setUrl(value);
					break;
				case "urlShort":
					entity.setUrlShort(value);
					break;
				case "parentUrl":
					entity.setParentUrl(value);
					break;
				case "parentUrlShort":
					entity.setParentUrlShort(value);
					break;
				case "rootUrlId":
					entity.setRootUrlId(Long.parseLong(value));
					break;
				case "containStr":
					entity.setContainStr(value);
					break;
				default:
					break;
				}
			}
			list.add(entity);
		}
		//批量插入
		crawlTaskDao.batchInsert(list);
	}
	
	/**
	 * 上传子页面
	 * 将json以文件的形式保存在暂存目录
	 * @param jsonStr 任务列表json串
	 * @author ServerZhang
	 * @date 2018年1月11日
	 */
	@Override
	public void uploadSubpage(String jsonStr){
		String uuid = StringUtil.getUUID();
		//将json以文件的形式保存在暂存目录
		if (StringUtil.isEmpty(htmlTempPath)) {
			htmlTempPath = "./temp/";
		}
		File pFile = new File(htmlTempPath);
		if (!pFile.exists()) {
			pFile.mkdirs();
		}
		String path = StringUtil.connectAsFilePath(htmlTempPath,uuid+".json");
		File jsonFile = new File(path);
		
		FileOutputStream fos = null;
		Writer writer = null;
		try {
			fos = new FileOutputStream(jsonFile);
			writer = new OutputStreamWriter(fos, "UTF-8");
			writer.write(jsonStr);
			writer.flush();
			writer.close();
			fos.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			try {
				if (writer != null) {
					writer.close();
				}
				if (fos != null) {
					fos.close();
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		
	}
	/**
	 * 批量修改任务
	 * @param jsonStr 任务列表json串
	 * @author ServerZhang
	 * @date 2018年1月12日
	 */
	@Override
	public void updateTask(String jsonStr){
		List<CrawlTaskEntity> entities = new ArrayList<CrawlTaskEntity>();
		List<CrawlTaskWithHtmlDto> dtos = new ArrayList<CrawlTaskWithHtmlDto>();
		Long requestLogId = null;//请求日志唯一ID
		Long randomTaskId = null;//一组请求中的任意一个任务ID
		JSONArray jsonArray = new JSONArray(jsonStr);
		int length = jsonArray.length();
		if (length < 1) {
			return;
		}
		
		//此次提交中所有任务包含的所有父页面
		Map<Long, CrawlTask4ParentDto> map = new HashMap<Long, CrawlTask4ParentDto>();
		
		for(int i=0; i<length; i++){//遍历得到一个对象
			Object object = jsonArray.get(i);
			if (null == object) {
				continue;
			}
			CrawlTaskEntity entity = new CrawlTaskEntity();
			CrawlTaskWithHtmlDto dto = new CrawlTaskWithHtmlDto();
			entity.setCrawlStatus(CrawlStatusEnum.CRAWLED.getStatus());//完成
			
			Integer mailCount = 0;
			Integer phoneCount = 0;
			Integer titleCount = 0;
			Long parentId = null;
			
			JSONObject jsonObject = new JSONObject(object.toString());
			Iterator keys = jsonObject.keys();
			while(keys.hasNext()){//遍历对象中的键值
				Object keyObj = keys.next();
				if (StringUtil.isEmpty(keyObj)) {
					continue;
				}
				String key = keyObj.toString();
				Object valueObj = jsonObject.get(key);
				if (StringUtil.isEmpty(valueObj)) {
					continue;
				}
				String value = valueObj.toString();
				switch (key) {
				case "id":
					if (randomTaskId == null) {
						randomTaskId = Long.parseLong(value);
					}
					entity.setId(Long.parseLong(value));
					break;
				case "parentId":
					parentId = Long.parseLong(value);
					break;
				case "requestStatus":
					entity.setRequestStatus(Integer.parseInt(value));
					break;
				case "mailCount":
					entity.setMailCount(Integer.parseInt(value));
					mailCount = Integer.parseInt(value);
					break;
				case "phoneCount":
					entity.setPhoneCount(Integer.parseInt(value));
					phoneCount = Integer.parseInt(value);
					break;
				case "titleCount":
					entity.setTitleCount(Integer.parseInt(value));
					titleCount = Integer.parseInt(value);
					break;
				case "requestLogId":
					if (requestLogId == null) {
						requestLogId = Long.parseLong(value);
					}
					break;
				case "storePath":
					entity.setStorePath(value);
					dto.setStorePath(value);
					break;
					
				case "urlShort":
					dto.setUrlShort(value);
					break;
				case "htmlStr":
					dto.setHtmlStr(value);
					break;
				default:
					break;
				}
			}
			entities.add(entity);
			dtos.add(dto);
			
			//修改父页面统计数据
			if (parentId != null && parentId > 0) {
				CrawlTask4ParentDto parentDto = map.get(parentId);
				if (parentDto == null) {
					parentDto = new CrawlTask4ParentDto();
					parentDto.setId(parentId);
					parentDto.setMailCountSub(mailCount);
					parentDto.setPhoneCountSub(phoneCount);
					parentDto.setTitleCountSub(titleCount);
				}else {
					Integer mailCountSub = parentDto.getMailCountSub();
					if (mailCountSub == null) {
						mailCountSub = mailCount;
					}else {
						mailCountSub += mailCount;
					}
					parentDto.setMailCountSub(mailCountSub);
					
					Integer phoneCountSub = parentDto.getPhoneCountSub();
					if (phoneCountSub == null) {
						phoneCountSub = phoneCount;
					}else {
						phoneCountSub += phoneCount;
					}
					parentDto.setPhoneCountSub(phoneCountSub);
					
					Integer titleCountSub = parentDto.getTitleCountSub();
					if (titleCountSub == null) {
						titleCountSub = titleCount;
					}else {
						titleCountSub += titleCount;
					}
					parentDto.setTitleCountSub(titleCountSub);
				}
				map.put(parentId, parentDto);
			}
		}
		
		//修改父页面包含的邮箱数、电话号码数、职称数
		if (map.size() > 0) {
			updateParent(map);
		}
		
		//批量更新
		if (entities.size() > 0) {
			crawlTaskDao.batchUpdate(entities);
		}
		//修改请求日志
		RequestLogDto logDto = new RequestLogDto();
		logDto.setClientStatus(ClientStatusEnum.WAITING.getStatus());//修改为待机状态
		logDto.setCompleteCount(entities.size());
		logDto.setCompleteTime(new Date());
		logDto.setTaskId(randomTaskId);

		// 上传文件
		Iterator<CrawlTaskWithHtmlDto> iterator = dtos.iterator();
		while (iterator.hasNext()) {
			CrawlTaskWithHtmlDto next = iterator.next();
			String htmlStr = next.getHtmlStr();
			String storePath = next.getStorePath();
			String urlShort = next.getUrlShort();
			if (StringUtil.isEmpty(htmlStr, storePath, urlShort)) {
				continue;
			}
			if (StringUtil.isEmpty(htmlStorePath)) {
				htmlStorePath = "./htmls/";
			}
			String folderPath = StringUtil.connectAsFilePath(htmlStorePath,
					storePath);
			File folder = new File(folderPath);
			if (!folder.exists()) {
				folder.mkdirs();
			}
			String realFilePath = folderPath + "/" + urlShort + ".html";
			File tempFile = new File(realFilePath);
			if (!tempFile.exists()) {
				try {
					tempFile.createNewFile();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}

			// 将html内容写入文件
			Writer writer = null;
			try {
				htmlStr = Base64Util.decrypt2Str(htmlStr);
				writer = new BufferedWriter(new OutputStreamWriter(
						new FileOutputStream(realFilePath), "UTF-8"));
				writer.write(htmlStr);
				writer.close();
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				try {
					if (writer != null) {
						writer.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
		requestLogDao.updateByTaksId(logDto);
	}
	
	/**
	 * 批量修改父网页包含的邮箱、手机号、职称数量
	 * @param map
	 * @author ServerZhang
	 * @date 2018年1月24日
	 */
	private void updateParent(Map<Long, CrawlTask4ParentDto> map){
		List<CrawlTaskEntity> entities = new ArrayList<CrawlTaskEntity>();
		Set<Entry<Long, CrawlTask4ParentDto>> entrySet = map.entrySet();
		Iterator<Entry<Long, CrawlTask4ParentDto>> iterator = entrySet.iterator();
		while(iterator.hasNext()){
			Entry<Long, CrawlTask4ParentDto> next = iterator.next();
			CrawlTask4ParentDto parentDto = next.getValue();
			CrawlTaskEntity entity = new CrawlTaskEntity();
			Long id = parentDto.getId();
			if (id == null) {
				continue;
			}
			entity.setId(id);
			entity.setMailCountSub(parentDto.getMailCountSub());
			entity.setPhoneCountSub(parentDto.getPhoneCountSub());
			entity.setTitleCountSub(parentDto.getTitleCountSub());
			entities.add(entity);
		}
		
		if (entities.size() > 0) {
			crawlTaskDao.batchUpdate(entities);
		}
		
	}
	/**
	 * list
	 * @param url
	 * @param parentUrl
	 * @param containStr
	 * @param rootUrlId
	 * @param status
	 * @param sortType
	 * @param pageIndex
	 * @param pageSize
	 * @return
	 * @author ServerZhang
	 * @date 2018年1月24日
	 */
	@Override
	public List<CrawlTaskEntity> list(String url, String parentUrl, String containStr,
			Long rootUrlId, Integer status, Integer sortType,Integer pageIndex,Integer pageSize) {
		PageHelper.startPage(pageIndex, pageSize);
		return crawlTaskDao.list(url, parentUrl, containStr, rootUrlId, status, sortType);
	}
	/**
	 * 任务统计分析
	 * @param url
	 * @param sortType 排序：0默认，1邮箱，2电话，3职称
	 * @param pageIndex
	 * @param pageSize
	 * @return
	 * @author ServerZhang
	 * @date 2018年1月24日
	 */
	@Override
	public List<CrawlTaskEntity> statistic(String url, Integer sortType, Integer pageIndex,Integer pageSize) {
		PageHelper.startPage(pageIndex, pageSize);
		
		return crawlTaskDao.statistic(url,sortType);
	}
}
